/**
 * 
 */
package com.yullage.ann.data;

import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import au.com.bytecode.opencsv.CSVReader;

/**
 * @author Steven Huang
 * 
 */
public class SomDataManager {

	private static final Logger logger = LoggerFactory.getLogger(SomDataManager.class);

	private List<List<Double>> trainingData;
	private List<List<Boolean>> trainingSimilarityMatrix;
	private List<List<Double>> testingData;
	private List<List<Boolean>> testingSimilarityMatrix;

	private List<List<Integer>> trainingIntraClassPairs;
	private List<List<Integer>> trainingInterClassPairs;
	private List<List<Integer>> testingIntraClassPairs;
	private List<List<Integer>> testingInterClassPairs;

	private int dataDimension = 0;

	public List<List<Double>> loadData(DataSetType dataSetType, String fileName) {
		List<List<Double>> data = new ArrayList<List<Double>>();

		try {
			CSVReader reader = new CSVReader(new FileReader(fileName), '\t');

			String[] nextLine;
			while ((nextLine = reader.readNext()) != null) {
				List<Double> point = new ArrayList<Double>();
				for (String value : nextLine) {
					point.add(Double.parseDouble(value));
				}
				data.add(point);
			}
		} catch (NumberFormatException | IOException e) {
			logger.error("Error loading training data!");
			e.printStackTrace();
		}

		if (dataSetType == DataSetType.TRAINING) {
			trainingData = data;
		} else {
			testingData = data;
		}

		calcDataDimension(data);
		return data;
	}

	public List<List<Boolean>> loadSimilarityMatrix(DataSetType dataSetType, String fileName) {
		List<List<Boolean>> similarityMatrix = new ArrayList<List<Boolean>>();

		try {
			CSVReader reader = new CSVReader(new FileReader(fileName), '\t');

			String[] nextLine;
			while ((nextLine = reader.readNext()) != null) {
				List<Boolean> entry = new ArrayList<Boolean>();
				for (String value : nextLine) {
					entry.add(value.trim().equals("1"));
				}
				similarityMatrix.add(entry);
			}
		} catch (NumberFormatException | IOException e) {
			logger.error("Error loading training data!");
			e.printStackTrace();
		}

		if (dataSetType == DataSetType.TRAINING) {
			trainingSimilarityMatrix = similarityMatrix;
		} else {
			testingSimilarityMatrix = similarityMatrix;
		}

		organizeSimilaritySet(dataSetType);
		return similarityMatrix;
	}

	public List<List<Double>> getData(DataSetType dataSetType) {
		if (dataSetType == DataSetType.TRAINING) {
			return trainingData;
		} else {
			return testingData;
		}
	}

	public List<Double> getDataByIndex(DataSetType dataSetType, int index) {
		if (dataSetType == DataSetType.TRAINING) {
			return trainingData.get(index);
		} else {
			return testingData.get(index);
		}
	}

	public void setData(DataSetType dataSetType, List<List<Double>> data) {
		if (dataSetType == DataSetType.TRAINING) {
			trainingData = data;
		} else {
			testingData = data;
		}

		calcDataDimension(data);
	}

	public List<List<Boolean>> getSimilarityMatrix(DataSetType dataSetType) {
		if (dataSetType == DataSetType.TRAINING) {
			return trainingSimilarityMatrix;
		} else {
			return testingSimilarityMatrix;
		}
	}

	public void setSimilarityMatrix(DataSetType dataSetType, List<List<Boolean>> similarityMatrix) {
		if (dataSetType == DataSetType.TRAINING) {
			trainingSimilarityMatrix = similarityMatrix;
		} else {
			testingSimilarityMatrix = similarityMatrix;
		}

		organizeSimilaritySet(dataSetType);
	}

	private void organizeSimilaritySet(DataSetType dataSetType) {
		List<List<Boolean>> similarityMatrix;
		List<List<Integer>> intraClass = new ArrayList<List<Integer>>();
		List<List<Integer>> interClass = new ArrayList<List<Integer>>();

		if (dataSetType == DataSetType.TRAINING) {
			similarityMatrix = trainingSimilarityMatrix;
			trainingIntraClassPairs = intraClass;
			trainingInterClassPairs = interClass;
		} else {
			similarityMatrix = testingSimilarityMatrix;
			testingIntraClassPairs = intraClass;
			testingInterClassPairs = interClass;
		}

		int totalDataCount = similarityMatrix.size();
		for (int i = 0; i < totalDataCount; i++) {
			for (int j = i + 1; j < totalDataCount; j++) {
				List<Integer> pair = new ArrayList<Integer>();
				pair.add(i);
				pair.add(j);

				if (similarityMatrix.get(i).get(j)) {
					intraClass.add(pair);
				} else {
					interClass.add(pair);
				}
			}
		}
	}

	public List<List<Integer>> getIntraClassPairs(DataSetType dataSetType) {
		if (dataSetType == DataSetType.TRAINING) {
			return trainingIntraClassPairs;
		} else {
			return testingIntraClassPairs;
		}
	}

	public List<List<Integer>> getInterClassPairs(DataSetType dataSetType) {
		if (dataSetType == DataSetType.TRAINING) {
			return trainingInterClassPairs;
		} else {
			return testingInterClassPairs;
		}
	}

	public int getDataSize(DataSetType dataSetType) {
		if (dataSetType == DataSetType.TRAINING) {
			return trainingData.size();
		} else {
			return testingData.size();
		}
	}

	private void calcDataDimension(List<List<Double>> data) {
		if ((data == null) || data.size() == 0) {
			dataDimension = 0;
		} else {
			dataDimension = data.get(0).size();
		}
	}

	public int getDataDimension() {
		return dataDimension;
	}

}
